package vip.xiaonuo.pm.modular.project.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.param.DeleteByIdParam;
import vip.xiaonuo.pm.modular.project.entity.PmProjectTypeEntity;
import vip.xiaonuo.pm.modular.project.mapper.PmProjectTypeMapper;
import vip.xiaonuo.pm.modular.project.param.PmProjectTypeAddParam;
import vip.xiaonuo.pm.modular.project.param.PmProjectTypeEditParam;
import vip.xiaonuo.pm.modular.project.service.PmProjectTypeService;

import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 项目类型 服务实现类
 * </p>
 *
 * @author xhs
 * @since 2025-06-04
 */
@Service
public class PmProjectTypeServiceImp extends ServiceImpl<PmProjectTypeMapper, PmProjectTypeEntity> implements PmProjectTypeService {

    /**
     * 根据ID查询数据
     *
     * @param id 入参
     * @return PmProjectTypeEntity
     */
    @Override
    public PmProjectTypeEntity queryEntityById(String id) {
        PmProjectTypeEntity projectTypeEntity = this.getById(id);
        if (ObjectUtil.isEmpty(projectTypeEntity)) {
            throw new CommonException("项目类型不存在，id值为：{}", id);
        }
        return projectTypeEntity;
    }

    /**
     * 新增项目类型
     *
     * @param pmProjectTypeAddParam 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(PmProjectTypeAddParam pmProjectTypeAddParam) {
        // 1.校验数据
        checkParam(pmProjectTypeAddParam);
        PmProjectTypeEntity pmProjectTypeEntity = BeanUtil.toBean(pmProjectTypeAddParam, PmProjectTypeEntity.class);
        // 2.保存数据
        this.save(pmProjectTypeEntity);
    }

    private void checkParam(PmProjectTypeAddParam pmProjectTypeAddParam) {
        boolean hasParentProjectTypeName = this.count(new LambdaQueryWrapper<PmProjectTypeEntity>()
                .eq(PmProjectTypeEntity::getParentId, pmProjectTypeAddParam.getParentId())
                .eq(PmProjectTypeEntity::getProjectTypeName, pmProjectTypeAddParam.getProjectTypeName())
        ) > 0;
        if (hasParentProjectTypeName) {
            throw new CommonException("存在重复的项目类型，名称为：{}", pmProjectTypeAddParam.getProjectTypeName());
        }
    }

    /**
     * 编辑项目类型
     *
     * @param pmProjectTypeEditParam 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(PmProjectTypeEditParam pmProjectTypeEditParam) {
        // 校验数据
        checkParam(pmProjectTypeEditParam);
        PmProjectTypeEntity typeEntity = queryEntityById(pmProjectTypeEditParam.getId());
        BeanUtil.copyProperties(pmProjectTypeEditParam, typeEntity);
        // 更新项目类型
        this.updateById(typeEntity);
    }

    private void checkParam(PmProjectTypeEditParam pmProjectTypeEditParam) {
        boolean hasProjectTypeCheck = this.count(new LambdaQueryWrapper<PmProjectTypeEntity>()
                .ne(PmProjectTypeEntity::getId, pmProjectTypeEditParam.getId())
                .eq(PmProjectTypeEntity::getProjectTypeName, pmProjectTypeEditParam.getProjectTypeName())
                .eq(PmProjectTypeEntity::getParentId, pmProjectTypeEditParam.getParentId())
        ) > 0;
        if (hasProjectTypeCheck) {
            throw new CommonException("存在重复的项目类型，名称为：{}", pmProjectTypeEditParam.getProjectTypeName());
        }
    }

    /**
     * 删除项目类型
     *
     * @param DeleteIdParamList 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<DeleteByIdParam> DeleteIdParamList) {
        List<String> projectTypeIdList = CollStreamUtil.toList(DeleteIdParamList, DeleteByIdParam::getId);
        if (ObjectUtil.isNotEmpty(projectTypeIdList)) {
            // 查询删除的项目类型下是否存在孩子节点的数据
            List<PmProjectTypeEntity> parentIdList = this.list(new LambdaQueryWrapper<PmProjectTypeEntity>()
                    .in(PmProjectTypeEntity::getParentId, projectTypeIdList));
            if (ObjectUtil.isNotEmpty(parentIdList)) {
                throw new CommonException("存在关联子节点数据，请先删除子节点数据");
            }
            List<PmProjectTypeEntity> projectTypeEntityList = this.list(new LambdaQueryWrapper<PmProjectTypeEntity>()
                    .in(PmProjectTypeEntity::getId, projectTypeIdList));
            if (ObjectUtil.isEmpty(projectTypeEntityList)) {
                throw new CommonException("数据不存在，请刷新页面");
            }
            // 执行删除
            this.removeByIds(projectTypeIdList);
        }
    }

    /**
     * 获取项目类型树
     *
     * @return CommonResult<List < Tree < String>>>
     */
    @Override
    public List<Tree<String>> tree() {
        QueryWrapper<PmProjectTypeEntity> queryWrapper = new QueryWrapper<PmProjectTypeEntity>().checkSqlInjection();
        queryWrapper.lambda().orderByAsc(PmProjectTypeEntity::getSortCode);
        List<PmProjectTypeEntity> list = this.list(queryWrapper);
        // 填充上层的父级项目类型
        this.fillParentProjectType(list);
        List<TreeNode<String>> treeNodeList = list.stream().map(projectType ->
                        new TreeNode<>(projectType.getId(), projectType.getParentId(),
                                projectType.getProjectTypeName(), projectType.getSortCode()).setExtra(JSONUtil.parseObj(projectType)))
                .collect(Collectors.toList());
        return TreeUtil.build(treeNodeList, "0");
    }

    /**
     * 填充上层的父级项目类型
     *
     * @param list 入参
     */
    private void fillParentProjectType(List<PmProjectTypeEntity> list) {
        if (CollUtil.isNotEmpty(list)) {
            List<PmProjectTypeEntity> typeEntityList = list.stream().filter(distinctByKey(PmProjectTypeEntity::getParentId)).collect(Collectors.toList());
            List<String> parentIds = null;
            if (CollUtil.isNotEmpty(typeEntityList)) {
                parentIds = CollUtil.newArrayList();
                for (PmProjectTypeEntity projectType : typeEntityList) {
                    if (!StrUtil.equals(projectType.getParentId(), "0")) {
                        parentIds.add(projectType.getParentId());
                    }
                }
            }
            if (CollUtil.isNotEmpty(parentIds)) {
                LambdaQueryWrapper<PmProjectTypeEntity> projectTypeLambdaQueryWrapper = new LambdaQueryWrapper<>();
                projectTypeLambdaQueryWrapper.in(PmProjectTypeEntity::getId, parentIds);
                List<PmProjectTypeEntity> parentSysMenus = this.list(projectTypeLambdaQueryWrapper);
                if (CollUtil.isNotEmpty(parentSysMenus)) {
                    this.fillParentProjectType(parentSysMenus);
                    list.addAll(parentSysMenus);
                }
            }
        }
    }

    /**
     * 去重
     *
     * @param keyExtractor 入参
     * @return Predicate<T>
     */
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }
}
